/*
 * BPlusTreeNode.cpp
 *
 *  Created on: 16-Oct-2013
 *      Author: sriram
 */
#include <math.h>
#include "BPlusTreeNode.h"
#include "BPlusTree.h"
#include "../dependency/StatusCodes.h"
#include "../BufferManager/BufferManager.h"
#include "IndexUtil.h"
#include "BPlusTreeLeafNode.h"
BPlusTreeNode::BPlusTreeNode() {
	// TODO Initialize constructor
    isIndexGenerated = false;
}

BPlusTreeNode::BPlusTreeNode(int nodePageNumber){
    BufferManager *buffManager = BufferManager::getInstance();
    int err = buffManager->getPage(nodePageNumber, pageData_);
    if(err!=SUCCESS){
        DEBUG_B("ERROR CREATING THE NODE");
    }
    memcpy(&generalNodePageHeader_, pageData_, sizeof(generalNodePageHeader_));
    int indexPageNumber = generalNodePageHeader_.indexHeaderPGNumber;
    indexHeaderPage_ = new IndexHeaderPage(indexPageNumber);
    isIndexGenerated = true;
}

BPlusTreeNode::BPlusTreeNode(IndexHeaderPage *indexHeaderPage, int indexPageNumber) {
	//	DEBUG_B("Creating index page with page number : "<<indexPageNumber)
	isIndexGenerated = false;
	indexHeaderPage_ = indexHeaderPage;
	pageData_ = NULL;
	BufferManager *bufMgr = BufferManager::getInstance();
	bufMgr->getPage(indexPageNumber, pageData_);
	memcpy(&generalNodePageHeader_, pageData_,BPlusTreeNode::getBPlusGeneralNodeHeaderSize());
}

BPlusTreeNode::~BPlusTreeNode() {
	// TODO Auto-generated destructor stub
    BufferManager *bufMgr = BufferManager::getInstance();
    DEBUG_B("Unpinning and Saving!!!");
	bufMgr->releasePage(generalNodePageHeader_.pgHeader.pageNumber, true);
    if(isIndexGenerated)
        delete indexHeaderPage_;
}

int BPlusTreeNode::getBPlusGeneralNodeHeaderSize() {
    return sizeof(GeneralNodeStruct);
}

// Searches for a key and returns the page number which may contain the key
int BPlusTreeNode::search(char *key){
    int offset = BPlusTreeNode::getBPlusGeneralNodeHeaderSize();
	char *tempKey = new char[indexHeaderPage_->getKeySize()];
	int leftPageNumber, rightPageNumber;
	for (int i = 0; i < this->generalNodePageHeader_.noKeys; i++) {
		memcpy(&leftPageNumber, &pageData_[offset], sizeof(int));
		offset = offset + sizeof(int);
		memcpy(tempKey, &pageData_[offset], indexHeaderPage_->getKeySize());
		offset = offset + indexHeaderPage_->getKeySize();
		memcpy(&rightPageNumber, &pageData_[offset], sizeof(int));
		int compValue = IndexUtil::compareKeys(tempKey, key, indexHeaderPage_);
		if (compValue == 0){
            // Here there is a possibility of getting some left node with key = the key
            // Consider case of splitting Max records leaf with identical values
            int retValue = 1; // Not present in left page
            if(getLevel() == 1){
                // Child is a leaf
                BPlusTreeLeafNode bLeaf(indexHeaderPage_, leftPageNumber);
                retValue = bLeaf.contains(key);                
            } else {
                // Child is non leaf
                BPlusTreeNode bChild(indexHeaderPage_, leftPageNumber);
                retValue = bChild.contains(key);
            }
            delete tempKey;
            if(retValue==0) return leftPageNumber;
			else return rightPageNumber;
        }
		if (compValue == 1){
            delete tempKey;
			return leftPageNumber;
        }
		//DEBUG_B("found left page Number "<<leftPageNumber);
	}
	memcpy(&rightPageNumber, &pageData_[offset], sizeof(int));
	offset = offset + sizeof(int);
    delete tempKey;
	return rightPageNumber;
}

// Searches for a key and returns the page number which may contain the key
// Compares only the first noColumns of the key
int BPlusTreeNode::search(char *key, int noColumns){
    int offset = BPlusTreeNode::getBPlusGeneralNodeHeaderSize();
	char *tempKey = new char[indexHeaderPage_->getKeySize()];
	int leftPageNumber, rightPageNumber;
	for (int i = 0; i < this->generalNodePageHeader_.noKeys; i++) {
		memcpy(&leftPageNumber, &pageData_[offset], sizeof(int));
		offset = offset + sizeof(int);
		memcpy(tempKey, &pageData_[offset], indexHeaderPage_->getKeySize());
		offset = offset + indexHeaderPage_->getKeySize();
		memcpy(&rightPageNumber, &pageData_[offset], sizeof(int));
		int compValue = IndexUtil::compareKeys(tempKey, key, noColumns, indexHeaderPage_);
		if (compValue == 0){
            // Here there is a possibility of getting some left node with key = the key
            // Consider case of splitting Max records leaf with identical values
            int retValue = 1; // Not present in left page
            if(getLevel() == 1){
                // Child is a leaf
                BPlusTreeLeafNode bLeaf(indexHeaderPage_, leftPageNumber);
                retValue = bLeaf.containsColumns(key, noColumns);                
            } else {
                // Child is non leaf
                BPlusTreeNode bChild(indexHeaderPage_, leftPageNumber);
                retValue = bChild.containsColumns(key, noColumns);
            }
            delete tempKey;
            if(retValue==0) return leftPageNumber;
			else return rightPageNumber;
        }
		if (compValue == 1){
            delete tempKey;
			return leftPageNumber;
        }
		//DEBUG_B("found left page Number "<<leftPageNumber);
	}
	memcpy(&rightPageNumber, &pageData_[offset], sizeof(int));
	offset = offset + sizeof(int);
    delete tempKey;
	return rightPageNumber;
}

// Searches for a key and returns the page number which may contain the key
int BPlusTreeNode::insertsearch(char *key){
    int offset = BPlusTreeNode::getBPlusGeneralNodeHeaderSize();
	char *tempKey = new char[indexHeaderPage_->getKeySize()];
	int leftPageNumber, rightPageNumber;
	for (int i = 0; i < this->generalNodePageHeader_.noKeys; i++) {
		memcpy(&leftPageNumber, &pageData_[offset], sizeof(int));
		offset = offset + sizeof(int);
		memcpy(tempKey, &pageData_[offset], indexHeaderPage_->getKeySize());
		offset = offset + indexHeaderPage_->getKeySize();
		memcpy(&rightPageNumber, &pageData_[offset], sizeof(int));
		int compValue = IndexUtil::compareKeys(tempKey, key, indexHeaderPage_);
		if (compValue == 0){
            delete tempKey;
            return rightPageNumber;
        }
		if (compValue == 1){
            delete tempKey;
			return leftPageNumber;
        }
		//DEBUG_B("found left page Number "<<leftPageNumber);
	}
	memcpy(&rightPageNumber, &pageData_[offset], sizeof(int));
	offset = offset + sizeof(int);
    delete []tempKey;
	return rightPageNumber;
}

// returns 0 if the node contains key, 1 otherwise
int BPlusTreeNode::contains(char *key){
    int offset = BPlusTreeNode::getBPlusGeneralNodeHeaderSize();
	char *tempKey = new char[indexHeaderPage_->getKeySize()];
	int leftPageNumber, rightPageNumber;
	for (int i = 0; i < this->generalNodePageHeader_.noKeys; i++) {
		offset = offset + sizeof(int);
		memcpy(tempKey, &pageData_[offset], indexHeaderPage_->getKeySize());
		offset = offset + indexHeaderPage_->getKeySize();
		int compValue = IndexUtil::compareKeys(tempKey, key, indexHeaderPage_);
		if (compValue == 0){
            delete tempKey;
			return 0;
        }
	}
    delete []tempKey;
	return 1;
}

// returns 0 if the node contains key, 1 otherwise
// Compares only the first noColumns of the key
int BPlusTreeNode::containsColumns(char *key, int noColumns){
    int offset = BPlusTreeNode::getBPlusGeneralNodeHeaderSize();
	char *tempKey = new char[indexHeaderPage_->getKeySize()];
	for (int i = 0; i < this->generalNodePageHeader_.noKeys; i++) {
		offset = offset + sizeof(int);
		memcpy(tempKey, &pageData_[offset], indexHeaderPage_->getKeySize());
		offset = offset + indexHeaderPage_->getKeySize();
		int compValue = IndexUtil::compareKeys(tempKey, key, noColumns, indexHeaderPage_);
		if (compValue == 0){
            delete tempKey;
			return 0;
        }
	}
    delete []tempKey;
	return 1;
}
// node.create();
// Creates an BPlusTreeNode Page for a given IndexHeaderPage type
STATUS_CODE BPlusTreeNode::create(IndexHeaderPage* indexHeaderPage) {
	BufferManager *bufMgr = BufferManager::getInstance();
	int newPageNumber;
	int error = bufMgr->getNewPage(newPageNumber, pageData_);
	if (error != SUCCESS) {
		DEBUG_B("ERROR IN CREATE INDEX PAGE");
		return error;
	}
	memcpy(&generalNodePageHeader_, pageData_, sizeof(generalNodePageHeader_));
	generalNodePageHeader_.pgHeader.pageType=TYPE_INDEX_PAGE;
	generalNodePageHeader_.leftPGNumber = -1;
	generalNodePageHeader_.rightPGNumber = -1;
	generalNodePageHeader_.level = 1;// Minimum Level
	generalNodePageHeader_.noKeys = 0;
	generalNodePageHeader_.parentPGNumber = -1;
    generalNodePageHeader_.indexHeaderPGNumber = indexHeaderPage->getPageNumber();
	memcpy(pageData_, &generalNodePageHeader_, sizeof(generalNodePageHeader_));
	//	indexHeaderPage->pushIndexPageNumbers(newPageNumber);
	indexHeaderPage_ = indexHeaderPage;
	return SUCCESS;
}

// Adds the key + page into the node at front...
// TODO -- Check for necessity to fix the child left and right pointers..
STATUS_CODE BPlusTreeNode::insertFront(const char *key, int leftPageNumber){
    int headerSize = BPlusTreeNode::getBPlusGeneralNodeHeaderSize();
    int keySize = indexHeaderPage_->getKeySize();
    int noKeys = getNoKeys();
    int i=0;
    int offset, shiftOffset;
    
    // Shifting the keys to right by one (key + page)
    for(i=noKeys-1; i>=0; i--){
        offset = headerSize + sizeof(int) + i*(sizeof(int)+keySize);
        shiftOffset = offset + (sizeof(int)+keySize);
        memcpy(&pageData_[shiftOffset], &pageData_[offset], sizeof(int)+keySize);
    }
    offset = headerSize;
    shiftOffset = offset + (sizeof(int)+keySize);
    memcpy(&pageData_[shiftOffset], &pageData_[offset], sizeof(int));
    
    // Storing given key + page to start
    memcpy(&pageData_[offset], &leftPageNumber, sizeof(int));
    offset += sizeof(int);
    memcpy(&pageData_[offset], key, keySize);

    // Fixing children nodes
    if(getLevel()==1){
        BPlusTreeLeafNode bLeft(indexHeaderPage_, leftPageNumber);
        bLeft.setParentPgNumber(getPageNumber());
    } else{
        BPlusTreeNode bLeft(indexHeaderPage_, leftPageNumber);
        bLeft.setParentPageNumber(getPageNumber());
    }
    setNoKeys(getNoKeys() + 1);
    return SUCCESS;
}

// Appends the key + page into the node...
// TODO -- Check for necessity to fix the child left and right pointers..
STATUS_CODE BPlusTreeNode::append(const char *key, int rightPageNumber){
    int offset = BPlusTreeNode::getBPlusGeneralNodeHeaderSize();
    int keySize = indexHeaderPage_->getKeySize();
    offset += getNoKeys()*(keySize + sizeof(int));
    int leftPage=-1;
    memcpy(&leftPage, &pageData_[offset], sizeof(int));
    offset += sizeof(int);
    memcpy(&pageData_[offset], key, keySize);
    offset += keySize;
    memcpy(&pageData_[offset], &rightPageNumber, sizeof(int));
    // Fixing children nodes
    if(getLevel()==1){
        BPlusTreeLeafNode bLeft(indexHeaderPage_, leftPage);
        BPlusTreeLeafNode bRight(indexHeaderPage_, rightPageNumber);
//        bRight.setRightPgNumber(bLeft.getRightPgNumber());
//        bLeft.setRightPgNumber(rightPageNumber);
//        bRight.setLeftPgNumber(leftPage);
        bRight.setParentPgNumber(getPageNumber());
    } else{
        BPlusTreeNode bLeft(indexHeaderPage_, leftPage);
        BPlusTreeNode bRight(indexHeaderPage_, rightPageNumber);
//        bRight.setRightPageNumber(bLeft.getRightPageNumber());
//        bLeft.setRightPageNumber(rightPageNumber);
//        bRight.setLeftPageNumber(leftPage);
        bRight.setParentPageNumber(getPageNumber());
    }
    setNoKeys(getNoKeys() + 1);
    return SUCCESS;
}


// Inserts the input key into the node
STATUS_CODE BPlusTreeNode::insert(const char *key, int leftPageNumber, int rightPageNumber){
    DEBUG_B("Inserting into an General BPlusTree NOde");
    int level = indexHeaderPage_->getHeight();
    int keySize = indexHeaderPage_->getKeySize();
    
    if(level==0){
        // This node is about to be the root of the tree
        // This happens only while splitting the first leaf node...
        DEBUG_B("General Node, Position of Insertion: Root Node"<<IndexUtil::keyToString(key, indexHeaderPage_));
        indexHeaderPage_->setRootPageNumber(generalNodePageHeader_.pgHeader.pageNumber);
        indexHeaderPage_->setHeight(level + 1); // 1 implicitly
        int offset = BPlusTreeNode::getBPlusGeneralNodeHeaderSize();
        memcpy(&pageData_[offset], &leftPageNumber, sizeof(int));
        offset += sizeof(int);
        memcpy(&pageData_[offset], key, keySize);
        offset += keySize;
        memcpy(&pageData_[offset], &rightPageNumber, sizeof(int));
        generalNodePageHeader_.noKeys++; 
        memcpy(pageData_, &generalNodePageHeader_, sizeof(generalNodePageHeader_));
        BPlusTreeLeafNode leftNode(indexHeaderPage_, leftPageNumber);
        BPlusTreeLeafNode rightNode(indexHeaderPage_, rightPageNumber);
        leftNode.setParentPgNumber(generalNodePageHeader_.pgHeader.pageNumber);
        rightNode.setParentPgNumber(generalNodePageHeader_.pgHeader.pageNumber);
        return SUCCESS;
    } else {
        // If the node is not the root
        if(generalNodePageHeader_.noKeys==0){
            // If the node is empty
            int keySize = indexHeaderPage_->getKeySize();
            int offset = BPlusTreeNode::getBPlusGeneralNodeHeaderSize();
            memcpy(&pageData_[offset], &leftPageNumber, sizeof(int));
            offset += sizeof(int);
            memcpy(&pageData_[offset], key, keySize);
            offset += keySize;
            memcpy(&pageData_[offset], &rightPageNumber, sizeof(int));
            generalNodePageHeader_.noKeys++;
            memcpy(pageData_, &generalNodePageHeader_, sizeof(generalNodePageHeader_));
            if(getLevel()==1){
                // Children are leafs
                BPlusTreeLeafNode bLeaf1(indexHeaderPage_, leftPageNumber);
                BPlusTreeLeafNode bLeaf2(indexHeaderPage_, rightPageNumber);
                bLeaf1.setParentPgNumber(getPageNumber());
                bLeaf2.setParentPgNumber(getPageNumber());
            } else{
                BPlusTreeNode bNode1(indexHeaderPage_, leftPageNumber);
                BPlusTreeNode bNode2(indexHeaderPage_, rightPageNumber);
                bNode1.setParentPageNumber(getPageNumber());
                bNode2.setParentPageNumber(getPageNumber());
            }
            return SUCCESS;
        } else if(generalNodePageHeader_.noKeys != indexHeaderPage_->getFanOut()){
            // If the node is not full
            int keySize = indexHeaderPage_->getKeySize();
            int tempLeftPage, tempRightPage;
            char *tempKey = new char[keySize];
            int offset = BPlusTreeNode::getBPlusGeneralNodeHeaderSize();
            
            // Trying to insert the key in its appropriate position at i...
            int i;
            for(i=0; i<generalNodePageHeader_.noKeys; i++){
                memcpy(&tempLeftPage, &pageData_[offset], sizeof(int));
                offset += sizeof(int);
                memcpy(tempKey, &pageData_[offset], sizeof(keySize));
                offset += keySize;
                memcpy(&tempRightPage, &pageData_[offset], sizeof(int));
                int cmpValue = IndexUtil::compareKeys(tempKey, key, indexHeaderPage_);
                if(cmpValue == 1){
                    DEBUG_B("General Node, Position of Insertion: "<<i<<", "<<
                            IndexUtil::keyToString(tempKey, indexHeaderPage_)<<" And "<<
                            IndexUtil::keyToString(key, indexHeaderPage_));
                    // Have to insert in ith position... 
                    // shift rest of the (n-i) pages
                    for(int j=generalNodePageHeader_.noKeys; j>i; j--){
                        int shiftOffset = BPlusTreeNode::getBPlusGeneralNodeHeaderSize() + sizeof(int) +
                                        (sizeof(int)+keySize)*(j-1);
                        int nextShift = shiftOffset + (sizeof(int)+keySize);
                        memcpy(&pageData_[nextShift], &pageData_[shiftOffset], sizeof(int)+keySize);
                    }
                    // Going to the leftPageNumber of the ith key...
                    int insertOffset = BPlusTreeNode::getBPlusGeneralNodeHeaderSize() + (sizeof(int)+keySize)*i;
                    memcpy(&pageData_[insertOffset], &leftPageNumber, sizeof(int));
                    insertOffset += sizeof(int);
                    memcpy(&pageData_[insertOffset], key, keySize);
                    insertOffset += keySize;
                    memcpy(&pageData_[insertOffset], &rightPageNumber, sizeof(int));
                    insertOffset += sizeof(int);
                    
                    // Setting up the new left page and right page node
                    // The rightpage to the actual (i-1)th node (before insertion) 
                    // and the left page to the actual ith node gets changed after this insertion
                    if(getLevel()==1){
                        // Children are leafs
                        BPlusTreeLeafNode bLeafActualILeft(tempLeftPage);
                        BPlusTreeLeafNode bLeafActualIRight(tempRightPage);
                        BPlusTreeLeafNode bLeafNowILeft(leftPageNumber);
                        BPlusTreeLeafNode bLeafNowIRight(rightPageNumber);
                        
                        bLeafNowILeft.setRightPgNumber(rightPageNumber);
                        bLeafNowIRight.setLeftPgNumber(leftPageNumber);
                        
                        // Both NowIRight & ActualILeft are same...
                        // Setting up new Right page...
                        bLeafNowIRight.setRightPgNumber(tempRightPage);
                        bLeafActualIRight.setLeftPgNumber(rightPageNumber);
                        
                        // Setting up parent nodes for the new page
                        bLeafNowILeft.setParentPgNumber(getPageNumber());
                        bLeafNowIRight.setParentPgNumber(getPageNumber());
                    } else {
                        // Children are non-leafs
                        BPlusTreeNode bNodeActualLeft(tempLeftPage);
                        BPlusTreeNode bNodeActualIRight(tempRightPage);
                        BPlusTreeNode bNodeNowILeft(leftPageNumber);
                        BPlusTreeNode bNodeNowIRight(rightPageNumber);
                        
                        bNodeNowILeft.setRightPageNumber(rightPageNumber);
                        bNodeNowIRight.setLeftPageNumber(leftPageNumber);
                        
                        // Both NowIRight & ActualILeft are same...
                        // Setting up new Right page...
                        bNodeNowIRight.setRightPageNumber(tempRightPage);
                        bNodeActualIRight.setLeftPageNumber(rightPageNumber);
                        
                        // Setting up parent nodes for the new page
                        bNodeNowILeft.setParentPageNumber(getPageNumber());
                        bNodeNowIRight.setParentPageNumber(getPageNumber());
                    }
                    generalNodePageHeader_.noKeys++;
                    memcpy(pageData_, &generalNodePageHeader_, sizeof(generalNodePageHeader_));
                    
                    delete tempKey;
                    return SUCCESS;
                } // End of if(comp)
            } // End of For
            // The key is being added to the end of the node
            if(i==generalNodePageHeader_.noKeys){
                DEBUG_B("General Node, Position of Insertion:(End of Node) "<<i<<", "<<IndexUtil::keyToString(key, indexHeaderPage_));                
                if(getLevel()==1){
                    // Children are leafs
                    BPlusTreeLeafNode bLeaf1(indexHeaderPage_, leftPageNumber);
                    BPlusTreeLeafNode bLeaf2(indexHeaderPage_, rightPageNumber);
                    
                    bLeaf1.setParentPgNumber(getPageNumber());
                    bLeaf2.setParentPgNumber(getPageNumber());
                    
                    bLeaf1.setRightPgNumber(rightPageNumber);
                    bLeaf2.setLeftPgNumber(leftPageNumber);
                    
                    if(bLeaf2.getRightPgNumber()!=-1){
                        BPlusTreeLeafNode bLeaf3(indexHeaderPage_, bLeaf2.getRightPgNumber());
                        bLeaf3.setLeftPgNumber(bLeaf2.getPageNumber());
                    }
                    
                } else{
                    // Children are non leafs
                    BPlusTreeNode bNode1(indexHeaderPage_, leftPageNumber);
                    BPlusTreeNode bNode2(indexHeaderPage_, rightPageNumber);
                    
                    bNode1.setParentPageNumber(getPageNumber());
                    bNode2.setParentPageNumber(getPageNumber());
                    
                    bNode1.setRightPageNumber(rightPageNumber);
                    bNode2.setLeftPageNumber(leftPageNumber);
                    
                    if(bNode2.getRightPageNumber()!=-1){
                        BPlusTreeNode bNode3(indexHeaderPage_, bNode2.getRightPageNumber());
                        bNode3.setLeftPageNumber(bNode2.getPageNumber());
                    }
                }
                
                int offset = BPlusTreeNode::getBPlusGeneralNodeHeaderSize();
                offset += (sizeof(int)+keySize)*generalNodePageHeader_.noKeys;
                
                memcpy(&pageData_[offset], &leftPageNumber, sizeof(int));
                offset += sizeof(int);
                memcpy(&pageData_[offset], key, keySize);
                offset += keySize;
                memcpy(&pageData_[offset], &rightPageNumber, sizeof(int));
                offset += sizeof(int);
                generalNodePageHeader_.noKeys++;
                memcpy(pageData_, &generalNodePageHeader_, sizeof(generalNodePageHeader_));
            }
            
            delete tempKey;
            return SUCCESS;
        } // End of if(noKeys<max) 
        else{
            // The node is full...
            DEBUG_B("General Node, Position of Insertion: Node Full"<<IndexUtil::keyToString(key, indexHeaderPage_));                
            int i;
            int noKeys = generalNodePageHeader_.noKeys;
            int tempLeftPage, tempRightPage;
            char *tempKey = new char[keySize];
            char **tempKeyStore = new char*[generalNodePageHeader_.noKeys+1];
            for(i=0; i<noKeys+1; i++)
                tempKeyStore[i] = new char[keySize];
            int *tempPagesStore = new int[generalNodePageHeader_.noKeys+2];
            
            
            bool isFound = false;
            
            int offset = BPlusTreeNode::getBPlusGeneralNodeHeaderSize();
            memcpy(&tempLeftPage, &pageData_[offset], sizeof(int));
            tempPagesStore[0] = tempLeftPage;
            
            // Storing all the keys and pages in the node
            // along with the key that is needed to be inserted...
            for(i=0; i< noKeys + 1; i++){
                if(i==noKeys && !isFound){
                    // If the key has to be inserted in last position
                    tempPagesStore[i] = leftPageNumber;
                    memcpy(tempKeyStore[i], key, keySize);
                    tempPagesStore[i+1] = rightPageNumber;
                    break;
                }
                memcpy(&tempLeftPage, &pageData_[offset], sizeof(int));
                offset += sizeof(int);
                memcpy(tempKey, &pageData_[offset], keySize);
                offset += keySize;
                memcpy(&tempRightPage, &pageData_[offset], sizeof(int));
                int cmpValue = IndexUtil::compareKeys(tempKey, key, indexHeaderPage_);
                if(cmpValue == 1 && !isFound){
                    isFound = true;
                    memcpy(tempKeyStore[i], key, keySize);
                    tempPagesStore[i] = leftPageNumber;
                    tempPagesStore[i+1] = rightPageNumber;
                    i++;
                    
                }
                memcpy(tempKeyStore[i], tempKey, keySize);
                tempPagesStore[i+1] = tempRightPage;                
            }
            /*
            
            cout<<"*******************************************************************"<<endl;
            for(i=0; i<noKeys+1; i++){
                cout<<IndexUtil::keyToString(tempKeyStore[i], indexHeaderPage_)<< " | ";
            }
            cout<<endl;
            cout<<"********************************************************************"<<endl;
            
             */ 
            /*
             // Displaying Complete node
            cout<<"["<<tempPagesStore[0]<<"] ";
            for(i=0; i<noKeys+1; i++){
                cout<<IndexUtil::keyToString(tempKeyStore[i], indexHeaderPage_)<<" ["<<tempPagesStore[i+1]<<"] ";
            }
            */
            offset = BPlusTreeNode::getBPlusGeneralNodeHeaderSize();
            // Copying half of the keys to the current node itself...
            for(i=0; i<(noKeys+1)/2; i++){
                // Saving Left page number
                memcpy(&pageData_[offset], &tempPagesStore[i], sizeof(int));
                offset += sizeof(int);
                if(generalNodePageHeader_.level == 1){
                    // Children are leafs
                    BPlusTreeLeafNode bLeaf(indexHeaderPage_, tempPagesStore[i]);
                    bLeaf.setParentPgNumber(getPageNumber());
                } else{
                    // Children are non leafs (internal nodes)
                    BPlusTreeNode bNode(indexHeaderPage_, tempPagesStore[i]);
                    bNode.setParentPageNumber(getPageNumber());
                }
                // Saving Key
                memcpy(&pageData_[offset], tempKeyStore[i], keySize);
                offset += keySize;
            }
            // Saving the last page
            memcpy(&pageData_[offset], &tempPagesStore[i], sizeof(int));
            generalNodePageHeader_.noKeys=(noKeys+1)/2;
            memcpy(pageData_, &generalNodePageHeader_, sizeof(generalNodePageHeader_));
            if(generalNodePageHeader_.level == 1){
                // Children are leafs
                BPlusTreeLeafNode bLeaf(indexHeaderPage_, tempPagesStore[i]);
                bLeaf.setParentPgNumber(getPageNumber());
            } else{
                // Children are non leafs (internal nodes)
                BPlusTreeNode bNode(indexHeaderPage_, tempPagesStore[i]);
                bNode.setParentPageNumber(getPageNumber());                
            }
            // Creating another Node for storing second half of keys
            DEBUG_B("General Node, Position of Insertion: Creating new node to Store keys"<<IndexUtil::keyToString(key, indexHeaderPage_));                            
            BPlusTreeNode bNode;
            bNode.create(indexHeaderPage_);
            bNode.setLevel(generalNodePageHeader_.level);
            // Setting right of the current node to the new node with second half of keys
            if(generalNodePageHeader_.rightPGNumber!=-1){
                BPlusTreeNode rightBNode(generalNodePageHeader_.rightPGNumber);
                rightBNode.setLeftPageNumber(bNode.getPageNumber());
            }
            bNode.setLeftPageNumber(getPageNumber());
            /*
            for(i=(noKeys+1)/2; i<noKeys+1; i++){
                cout<<" ["<<tempPagesStore[i]<<"] ";
                cout<<IndexUtil::keyToString(tempKeyStore[i], indexHeaderPage_);
                cout<<" ["<<tempPagesStore[i+1]<<"] ";
            }
            */
            
            // Add the promoted key - No need of promoted key in internal nodes - redundant
            // bNode.insert(tempKeyStore[(noKeys+1)/2], tempPagesStore[(noKeys+1)/2], 
               //     tempPagesStore[(noKeys+1)/2 + 1]);
            
            // Adding rest of the nodes and fixing the parent of their children
            for(i=(noKeys+1)/2 + 1; i<noKeys+1; i++){
                int tempLeftPage, tempRightPage;
                char *loopTempKey = new char[keySize];
                memcpy(loopTempKey, tempKeyStore[i], keySize);
                tempLeftPage = tempPagesStore[i];
                tempRightPage = tempPagesStore[i+1];
                
                bNode.insert(loopTempKey, tempLeftPage, tempRightPage);
                if(generalNodePageHeader_.level == 1){
                    // Children are leafs
                    BPlusTreeLeafNode bLeafLeft(indexHeaderPage_, tempLeftPage);
                    BPlusTreeLeafNode bLeafRight(indexHeaderPage_, tempRightPage);
                    bLeafLeft.setParentPgNumber(bNode.getPageNumber());
                    bLeafRight.setParentPgNumber(bNode.getPageNumber());
                } else{
                    // Children are non  leafs
                    BPlusTreeNode bNodeLeft(indexHeaderPage_, tempLeftPage);
                    BPlusTreeNode bNodeRight(indexHeaderPage_, tempRightPage);
                    bNodeLeft.setParentPageNumber(bNode.getPageNumber());
                    bNodeRight.setParentPageNumber(bNode.getPageNumber());
                }
                delete loopTempKey;
            } // End of for (inserting second half of the keys)
            // Promoting the center key to above level (Parent)
            char *promoteKey = new char[keySize];
            int promoteLeftPageNumber, promoteRightPageNumber;
            promoteLeftPageNumber = getPageNumber();
            promoteRightPageNumber = bNode.getPageNumber();
            memcpy(promoteKey, tempKeyStore[(noKeys+1)/2], keySize);
            
            // Check if there exists a parent to the node...
            if(generalNodePageHeader_.level == indexHeaderPage_->getHeight()){
                // Root node... No parent
                DEBUG_B("General Node, Position of Insertion: Splitting the Root"<<IndexUtil::keyToString(key, indexHeaderPage_));                                            
                
                BPlusTreeNode bRoot;
                bRoot.create(indexHeaderPage_);
                indexHeaderPage_->setRootPageNumber(bRoot.getPageNumber());
                indexHeaderPage_->setHeight(indexHeaderPage_->getHeight()+1);
                bRoot.setLevel(indexHeaderPage_->getHeight());
                bRoot.insert(promoteKey, promoteLeftPageNumber, promoteRightPageNumber);
                
                // Modifying the current node
                generalNodePageHeader_.leftPGNumber = -1;
                generalNodePageHeader_.rightPGNumber = bNode.getPageNumber();
                generalNodePageHeader_.parentPGNumber = bRoot.getPageNumber();
                memcpy(pageData_, &generalNodePageHeader_, sizeof(generalNodePageHeader_));
                
                bNode.setParentPageNumber(bRoot.getPageNumber());
                bNode.setLeftPageNumber(getPageNumber());
            }else{
                // Parent is present... We only need to try and insert key into parent
                BPlusTreeNode bParent(indexHeaderPage_, getParentPageNumber());
                bParent.insert(promoteKey, promoteLeftPageNumber, promoteRightPageNumber);
            }
            delete tempKey;
            delete promoteKey;
            delete tempPagesStore;
            for(i=0; i<noKeys+1; i++)
                delete []tempKeyStore[i];
            delete []tempKeyStore;
        }// End of else (if node is full)
        
    } // End of else (if node is not root)

    return SUCCESS;
}

STATUS_CODE BPlusTreeNode::remove(char *key, int nextPage, bool isRightMerge, vector<int> &arrDeletedPages){
    int noKeys = getNoKeys();
    int keySize = indexHeaderPage_->getKeySize();
    int possibleRoot = -1;
    if(isRightMerge){
        // If right merge then the key + preceeding page needs to be overridden
        int i, leftPageNumber = -1, rightPageNumber = -1;
        char *tempKey = new char[keySize];
        int offset = BPlusTreeNode::getBPlusGeneralNodeHeaderSize();
        memcpy(&leftPageNumber, &pageData_[offset], sizeof(int));
        offset += sizeof(int);
        for(i=0; i<noKeys; i++){
            memcpy(tempKey, &pageData_[offset], keySize);
            offset += keySize;
            memcpy(&rightPageNumber, &pageData_[offset], sizeof(int));
            offset += sizeof(int);
            if(IndexUtil::compareKeys(tempKey, key, indexHeaderPage_)==0 && rightPageNumber==nextPage){
                // key needed to be deleted
                break;
            }
            leftPageNumber = rightPageNumber;
        }
        if(i!=noKeys){
            // Key is found and is needed to be deleted... 
            int shiftoffset = offset - (keySize + sizeof(int)); // back to the key to be deleted
            int preceedingPageOffset = shiftoffset - sizeof(int);
            
            // Fixing the pointers of the children...
            if(getLevel()==1){
                // Children are leaf nodes
                BPlusTreeLeafNode bLeft(indexHeaderPage_, leftPageNumber);
                BPlusTreeLeafNode bRight(indexHeaderPage_, rightPageNumber);
                bRight.setLeftPgNumber(bLeft.getLeftPgNumber());
                if(bLeft.getLeftPgNumber()!=-1){
                    BPlusTreeLeafNode bLeftLeft(indexHeaderPage_, bLeft.getLeftPgNumber());
                    bLeftLeft.setRightPgNumber(rightPageNumber);
                }
            } else{
                // Children are non leafs
                BPlusTreeNode bLeft(indexHeaderPage_, leftPageNumber);
                BPlusTreeNode bRight(indexHeaderPage_, rightPageNumber);
                bRight.setLeftPageNumber(bLeft.getLeftPageNumber());
                if(bLeft.getLeftPageNumber()!=-1){
                    BPlusTreeNode bLeftLeft(indexHeaderPage_, bLeft.getLeftPageNumber());
                    bLeftLeft.setRightPageNumber(rightPageNumber);
                }
            }
            // Preceeding page of the page to be deleted gets fixed...
            memcpy(&pageData_[preceedingPageOffset], &rightPageNumber, sizeof(int));
            // Shifting the keys from here onwards
            int j; // Loop terminates if the key is the last one
            for(j=i+1; j<noKeys; j++){
                memcpy(&pageData_[shiftoffset], &pageData_[offset], sizeof(int)+keySize);                
                offset += (sizeof(int)+keySize);
                shiftoffset += (sizeof(int)+keySize);
            }
            setNoKeys(getNoKeys()-1);
            possibleRoot = rightPageNumber;
        }
        if(i==noKeys){
            // Key not found... 
            delete []tempKey;
            return FAILURE;
        } 
        delete []tempKey;
    } // End of if right merge
    else{
        // If left merge delete key + following page
        int i, leftPageNumber = -1, rightPageNumber = -1;
        char *tempKey = new char[keySize];
        int offset = BPlusTreeNode::getBPlusGeneralNodeHeaderSize();
        memcpy(&leftPageNumber, &pageData_[offset], sizeof(int));
        offset += sizeof(int);
        for(i=0; i<noKeys; i++){
            memcpy(tempKey, &pageData_[offset], keySize);
            offset += keySize;
            memcpy(&rightPageNumber, &pageData_[offset], sizeof(int));
            offset += sizeof(int);
            if(IndexUtil::compareKeys(tempKey, key, indexHeaderPage_)==0 && rightPageNumber==nextPage){
                // key needed to be deleted
                break;
            }
            leftPageNumber = rightPageNumber;
        }
        if(i!=noKeys){
            // Key is found and is needed to be deleted... 
            int shiftoffset = offset - (keySize + sizeof(int)); // back to the key to be deleted
            // Fixing the pointers of the children...
            if(getLevel()==1){
                // Children are leaf nodes
                BPlusTreeLeafNode bLeft(indexHeaderPage_, leftPageNumber);
                BPlusTreeLeafNode bRight(indexHeaderPage_, rightPageNumber);
                bLeft.setRightPgNumber(bRight.getRightPgNumber());
                if(bRight.getRightPgNumber()!=-1){
                    BPlusTreeLeafNode bRightRight(indexHeaderPage_, bRight.getRightPgNumber());
                    bRightRight.setLeftPgNumber(leftPageNumber);
                }
            } else{
                // Children are non leafs
                BPlusTreeNode bLeft(indexHeaderPage_, leftPageNumber);
                BPlusTreeNode bRight(indexHeaderPage_, rightPageNumber);
                bLeft.setRightPageNumber(bRight.getRightPageNumber());
                if(bRight.getRightPageNumber()!=-1){
                    BPlusTreeNode bRightRight(indexHeaderPage_, bRight.getRightPageNumber());
                    bRightRight.setLeftPageNumber(leftPageNumber);
                }
            }
            // Shifting the keys from here onwards
            int j; // Loop terminates if the key is the last one
            for(j=i+1; j<noKeys; j++){
                memcpy(&pageData_[shiftoffset], &pageData_[offset], sizeof(int)+keySize);                
                offset += (sizeof(int)+keySize);
                shiftoffset += (sizeof(int)+keySize);
            }
            setNoKeys(getNoKeys()-1);
            possibleRoot = leftPageNumber;
        }
        if(i==noKeys){
            // Key not found... 
            delete []tempKey;
            return FAILURE;
        } 
        delete []tempKey;
    }
    // Cases when the node becomes invalid...
    if(getNoKeys()==0){
        // This happens when ony 3 nodes are in tree and the only key from root is deleted.
        // possible root consists of the current root page number
        if(getLevel()==1){
            BPlusTreeLeafNode bLeaf(indexHeaderPage_, possibleRoot);
            indexHeaderPage_->setRootPageNumber(possibleRoot);
            bLeaf.setParentPgNumber(-1);
            indexHeaderPage_->setHeight(0);
        } else{
            BPlusTreeNode bNode(indexHeaderPage_, possibleRoot);
            indexHeaderPage_->setRootPageNumber(possibleRoot);
            bNode.setParentPageNumber(-1);
            indexHeaderPage_->setHeight(bNode.getLevel());
        }
        return SUCCESS;
    }
    if(getNoKeys()>= ceil(indexHeaderPage_->getFanOut()/2)){
        // This node has sufficient number of keys...
        return SUCCESS;
    } else{
        // We may have to deal with rotate or merge...
        int leftSiblingPage=-1, rightSiblingPage=-1;
        if(getParentPageNumber()!=-1){
            BPlusTreeNode bNode(indexHeaderPage_, getParentPageNumber());            
            bNode.getSiblingsToPage(getPageNumber(), leftSiblingPage, rightSiblingPage);
        }
        if(rightSiblingPage!=-1){
            // Try to rotate keys from right page
            BPlusTreeNode bRight(indexHeaderPage_, rightSiblingPage);
            if( bRight.getNoKeys()-1 >= ceil(indexHeaderPage_->getFanOut()/2) ){
                // We can rotate from right node
                char *rotateKey = new char[keySize];
                char *parentKey = new char[keySize];
                int rotatePageNumber;
                bRight.getFirstKey(rotateKey);
                bRight.getFirstPage(rotatePageNumber);

                BPlusTreeNode bParent(indexHeaderPage_, getParentPageNumber());
                bParent.getPrevKeytoPage(bRight.getPageNumber(), parentKey);
                append(parentKey, rotatePageNumber);
                bParent.updatePrevKeyToPageNumber(bRight.getPageNumber(), parentKey, rotateKey);
                
                if(getLevel() == 1){
                    // If child is leaf
                    BPlusTreeLeafNode bRotateNode(indexHeaderPage_, rotatePageNumber);
                    bRotateNode.setParentPgNumber(getPageNumber());
                } else{
                    // If child is not leaf
                    BPlusTreeNode bRotateNode(indexHeaderPage_, rotatePageNumber);
                    bRotateNode.setParentPageNumber(getPageNumber());
                }
                bRight.removeFirstPageKey();
                delete []parentKey;
                delete []rotateKey;
                return SUCCESS;
            }
        }
        if(leftSiblingPage!=-1){
            // Try to rotate keys from left page
            /* */
            BPlusTreeNode bLeft(indexHeaderPage_, leftSiblingPage);
            if( bLeft.getNoKeys()-1 >= ceil(indexHeaderPage_->getFanOut()/2) ){
                // We can rotate from left node
                char *rotateKey = new char[keySize];
                char *parentKey = new char[keySize];
                int rotatePageNumber;
                bLeft.getLastKey(rotateKey);
                bLeft.getLastPage(rotatePageNumber);
                BPlusTreeNode bParent(indexHeaderPage_, getParentPageNumber());
                bParent.getPrevKeytoPage(getPageNumber(), parentKey);
                insertFront(parentKey, rotatePageNumber);
                
                bParent.updatePrevKeyToPageNumber(getPageNumber(), parentKey, rotateKey);
                
                if(getLevel() == 1){
                    // If child is leaf
                    BPlusTreeLeafNode bRotateNode(indexHeaderPage_, rotatePageNumber);
                    bRotateNode.setParentPgNumber(getPageNumber());
                } else{
                    // If child is not leaf
                    BPlusTreeNode bRotateNode(indexHeaderPage_, rotatePageNumber);
                    bRotateNode.setParentPageNumber(getPageNumber());
                }
                bLeft.removeLastPageKey();
                
                delete []parentKey;
                delete []rotateKey;
                return SUCCESS;
              
            }
        }
         /* */
        //Rotation did not work out sofar. Try merging.            
        if(rightSiblingPage!=-1){
            // Try to merge with the right node.
            // This page needs to be deleted as its keys are merged to the right node
            arrDeletedPages.push_back(getPageNumber()); 
            BPlusTreeNode bParent(indexHeaderPage_, getParentPageNumber());
            BPlusTreeNode bRight(indexHeaderPage_, rightSiblingPage);
            char *parentKey = new char[keySize];
            char *tempKey = new char[keySize];
            // Adding parent key + last page of this node to the right node
            bParent.getPrevKeytoPage(rightSiblingPage, parentKey);
            int lastPage = -1;
            getLastPage(lastPage);
            bRight.insertFront(parentKey, lastPage);
            // Shifting the keys + pages of this node into the right node
            int headerSize = BPlusTreeNode::getBPlusGeneralNodeHeaderSize();
            int noKeys = getNoKeys();
            int i;
            for(i=noKeys-1; i>=0; i--){
                int offset = headerSize + i*(sizeof(int)+keySize);
                int tempPage=-1;
                memcpy(&tempPage, &pageData_[offset], sizeof(int));
                offset += sizeof(int);
                memcpy(tempKey, &pageData_[offset], keySize);
                bRight.insertFront(tempKey, tempPage);
            }

            // Deleting the parent key
            bParent.remove(parentKey, rightSiblingPage, true, arrDeletedPages);

            delete []tempKey;
            delete []parentKey;
            return SUCCESS;
        }
        if(leftSiblingPage!=-1){
            // Try to merge with the left node.
            // This page needs to be deleted as its keys are merged to the left node
            arrDeletedPages.push_back(getPageNumber()); 
            BPlusTreeNode bParent(indexHeaderPage_, getParentPageNumber());
            BPlusTreeNode bLeft(indexHeaderPage_, leftSiblingPage);
            char *parentKey = new char[keySize];
            char *tempKey = new char[keySize];
            // Adding parent key + first page of this node to the left node
            bParent.getPrevKeytoPage(getPageNumber(), parentKey);
            int firstPage = -1;
            getFirstPage(firstPage);
            bLeft.append(parentKey, firstPage);
            // Shifting the keys + pages of this node into the left node
            int offset = BPlusTreeNode::getBPlusGeneralNodeHeaderSize()+sizeof(int);
            int noKeys = getNoKeys();
            int i;
            for(i=0; i<noKeys; i++){
                int tempPage=-1;
                memcpy(tempKey, &pageData_[offset], keySize);
                offset += keySize;
                memcpy(&tempPage, &pageData_[offset], sizeof(int));
                offset += sizeof(int);
                bLeft.append(tempKey, tempPage);                
            }            
            // Deleting the parent key
            bParent.remove(parentKey, getPageNumber(), false, arrDeletedPages);
            delete []tempKey;
            delete []parentKey;
            return SUCCESS;            
        }
    }
    return SUCCESS;
}

int BPlusTreeNode::getPageNumber(){
    memcpy(&generalNodePageHeader_, pageData_, sizeof(generalNodePageHeader_));
    return generalNodePageHeader_.pgHeader.pageNumber;
}

int BPlusTreeNode::getIndexHeaderPageNumber(){
    memcpy(&generalNodePageHeader_, pageData_, sizeof(generalNodePageHeader_));
    return generalNodePageHeader_.indexHeaderPGNumber;
}

int BPlusTreeNode::getLevel(){
    memcpy(&generalNodePageHeader_, pageData_, sizeof(generalNodePageHeader_));
    return generalNodePageHeader_.level;
}

int BPlusTreeNode::getParentPageNumber(){
    memcpy(&generalNodePageHeader_, pageData_, sizeof(generalNodePageHeader_));
    return generalNodePageHeader_.parentPGNumber;
}

int BPlusTreeNode::getNoKeys(){
    memcpy(&generalNodePageHeader_, pageData_, sizeof(generalNodePageHeader_));
    return generalNodePageHeader_.noKeys;
}

int BPlusTreeNode::getLeftPageNumber(){
    memcpy(&generalNodePageHeader_, pageData_, sizeof(generalNodePageHeader_));
    return generalNodePageHeader_.leftPGNumber;
}

int BPlusTreeNode::getRightPageNumber(){
    memcpy(&generalNodePageHeader_, pageData_, sizeof(generalNodePageHeader_));
    return generalNodePageHeader_.rightPGNumber;
}

// Replaces the input key with input replaceKey value
STATUS_CODE BPlusTreeNode::updateKey(char *key, char *replaceKey){
    int noKeys = getNoKeys();
    int keySize = indexHeaderPage_->getKeySize();
    int offset = BPlusTreeNode::getBPlusGeneralNodeHeaderSize();
    // first page number
    offset += sizeof(int);
    int i;
    for(i=0; i<noKeys; i++){
        char *tempKey = new char[keySize];
        memcpy(tempKey, &pageData_[offset], keySize);
        // Both keys are same
        if(IndexUtil::compareKeys(tempKey, key, indexHeaderPage_)==0){
            memcpy(&pageData_[offset], replaceKey, keySize);
            delete tempKey;
            break;
        }
        offset += sizeof(int);
        delete tempKey;
    }
    if(i==noKeys){
        // Did not find the key in the immediate parent... go for the predecessor and check.
        if(getParentPageNumber()!=-1 && getLevel()<=indexHeaderPage_->getHeight()){
            // Has a parent
            BPlusTreeNode bNode(indexHeaderPage_, getParentPageNumber());
            bNode.updateKey(key, replaceKey);
        }
    }
    return SUCCESS;
}


// Updates key based on condition that the previous page is given.
STATUS_CODE BPlusTreeNode::updatePrevKeyToPageNumber(int pageNumber, char *key, char *replaceKey){
    int noKeys = getNoKeys();
    int keySize = indexHeaderPage_->getKeySize();
    int offset = BPlusTreeNode::getBPlusGeneralNodeHeaderSize();
    // first page number
    int tempPageNumber;
    memcpy(&tempPageNumber, &pageData_[offset], sizeof(int));
    offset += sizeof(int);
    if(tempPageNumber == pageNumber){
        if(getParentPageNumber()!=-1){
            BPlusTreeNode bParent(indexHeaderPage_, getParentPageNumber());
            bParent.updatePrevKeyToPageNumber(getPageNumber(), key, replaceKey);
        }
        return SUCCESS;
    }
    int i;
    for(i=0; i<noKeys; i++){
        char *tempKey = new char[keySize];
        memcpy(tempKey, &pageData_[offset], keySize);
        offset += keySize;
        memcpy(&tempPageNumber, &pageData_[offset], sizeof(int));
        offset += sizeof(int);
        // Both keys are same
        if(IndexUtil::compareKeys(tempKey, key, indexHeaderPage_)==0 && tempPageNumber==pageNumber){
            offset -= (keySize + sizeof(int));
            memcpy(&pageData_[offset], replaceKey, keySize);
            delete tempKey;
            break;
        }
        delete tempKey;
    }
    return SUCCESS;
}

void BPlusTreeNode::setPageNumber(int pageNumber){
    generalNodePageHeader_.pgHeader.pageNumber = pageNumber;
    memcpy(pageData_, &generalNodePageHeader_, sizeof(generalNodePageHeader_));
}

void BPlusTreeNode::setIndexHeaderPageNumber(int indexHeaderPageNumber){
    generalNodePageHeader_.indexHeaderPGNumber = indexHeaderPageNumber;
    memcpy(pageData_, &generalNodePageHeader_, sizeof(generalNodePageHeader_));
}

void BPlusTreeNode::setLevel(int level){
    generalNodePageHeader_.level = level;
    memcpy(pageData_, &generalNodePageHeader_, sizeof(generalNodePageHeader_));
}

void BPlusTreeNode::setParentPageNumber(int parentPageNumber){
    generalNodePageHeader_.parentPGNumber = parentPageNumber;
    memcpy(pageData_, &generalNodePageHeader_, sizeof(generalNodePageHeader_));
}

void BPlusTreeNode::setNoKeys(int noKeys){
    generalNodePageHeader_.noKeys = noKeys;
    memcpy(pageData_, &generalNodePageHeader_, sizeof(generalNodePageHeader_));
}

void BPlusTreeNode::setLeftPageNumber(int leftPageNumber){
    generalNodePageHeader_.leftPGNumber = leftPageNumber;
    memcpy(pageData_, &generalNodePageHeader_, sizeof(generalNodePageHeader_));
}

void BPlusTreeNode::setRightPageNumber(int rightPageNumber){
    generalNodePageHeader_.rightPGNumber = rightPageNumber;
    memcpy(pageData_, &generalNodePageHeader_, sizeof(generalNodePageHeader_));
}

// Gets the first valid Child Page number - useful for lever order traversal
int BPlusTreeNode::getFirstChildPageNumber(){
    int firstChildPageNumber=-1;
    int keySize = indexHeaderPage_->getKeySize();
    int offset = BPlusTreeNode::getBPlusGeneralNodeHeaderSize();
    int i=0;
    while(firstChildPageNumber==-1 && i<indexHeaderPage_->getNoKeys()+1){
        memcpy(&firstChildPageNumber, &pageData_[offset], sizeof(int));
        offset += sizeof(int)+keySize;
    }
    return firstChildPageNumber;
}

// Gets the Key and stores in the char* received in parameters
// Key is present previous to the page inputed
void BPlusTreeNode::getPrevKeytoPage(int page, char *key){
    int offset = BPlusTreeNode::getBPlusGeneralNodeHeaderSize();
    int noKeys = getNoKeys();
    int tempPage, i;
    int keySize = indexHeaderPage_->getKeySize();
    char *tempKey = new char[keySize];
    // first page
    memcpy(&tempPage, &pageData_[offset], sizeof(int));
    offset += sizeof(int);
    if(tempPage == page){
        key = NULL;
    } else {
        for(i=0; i<noKeys; i++){
            memcpy(tempKey, &pageData_[offset], keySize);
            offset += keySize;
            memcpy(&tempPage, &pageData_[offset], sizeof(int));
            offset += sizeof(int);
            if(page == tempPage){
                memcpy(key, tempKey, keySize);
                break;
            }
        }
    }
    delete []tempKey;
}

// Gets the Last Key and stores in the char* received in parameters
void BPlusTreeNode::getLastKey(char *key){
    int offset = BPlusTreeNode::getBPlusGeneralNodeHeaderSize();
    int keySize = indexHeaderPage_->getKeySize();
    int noKeys = getNoKeys();
    // first page
    offset += sizeof(int);
    // Rest of key + rid pairs
    offset += (sizeof(int)+keySize)*(noKeys-1);
    // Last key
    memcpy(key, &pageData_[offset], keySize);
}

// Returns the Last page - Stores in the parameter being sent
void BPlusTreeNode::getLastPage(int &lastPageNumber){
    int keySize = indexHeaderPage_->getKeySize();
    int noKeys = getNoKeys();    
    int offset = BPlusTreeNode::getBPlusGeneralNodeHeaderSize();
    // All page + key pairs at start
    offset += (sizeof(int)+keySize)*noKeys;
    // Last page
    memcpy(&lastPageNumber, &pageData_[offset], sizeof(int));
}

// Gets the First Key and stores in the char* received in parameters
void BPlusTreeNode::getFirstKey(char *key){
    int offset = BPlusTreeNode::getBPlusGeneralNodeHeaderSize();
    int keySize = indexHeaderPage_->getKeySize();
    // first page
    offset += sizeof(int);
    // First key
    memcpy(key, &pageData_[offset], keySize);
}
// Returns the First page 
void BPlusTreeNode::getFirstPage(int &firstPageNumber){
    int offset = BPlusTreeNode::getBPlusGeneralNodeHeaderSize();
    // first page
    memcpy(&firstPageNumber, &pageData_[offset], sizeof(int));
}

// Deletes the last page + last key
// Doesnot care on handling children left and right...
void BPlusTreeNode::removeLastPageKey(){
    setNoKeys(getNoKeys()-1);
}

// Deletes the first page + first key
// Doesnot care on handling children left and right...
void BPlusTreeNode::removeFirstPageKey(){
    int offset = BPlusTreeNode::getBPlusGeneralNodeHeaderSize();
    int keySize = indexHeaderPage_->getKeySize();
    int i, shiftOffset=0;
    for(i=1; i<getNoKeys(); i++){
        shiftOffset = offset + keySize + sizeof(int);
        memcpy(&pageData_[offset], &pageData_[shiftOffset], keySize + sizeof(int));
        offset += (keySize + sizeof(int));
    }
    shiftOffset = offset + keySize + sizeof(int);
    memcpy(&pageData_[offset], &pageData_[shiftOffset], sizeof(int));
    setNoKeys(getNoKeys()-1);
}

string BPlusTreeNode::toString(){
    ostringstream strStream;
    strStream << "********************** General BPlusTreeNode Page ***************************"<<endl;
    strStream << generalNodePageHeader_.pgHeader.toString() <<endl;
	strStream << "Index Header Page NO: " << getIndexHeaderPageNumber() << endl;
	strStream << "Level of Index Page" << getLevel() << endl;
	strStream << "Parent page number: "	<< getParentPageNumber() << endl;
	strStream << "Number of keys in Index Page: " << getNoKeys() << endl;
	strStream<< "*** DATA IN NODE ***"<<endl;
	int offset = BPlusTreeNode::getBPlusGeneralNodeHeaderSize();
	int leftPageNumber;
    int keySize = indexHeaderPage_->getKeySize();
	char *key = new char[keySize];
	for (int i = 0; i < getNoKeys(); i++) {
		memcpy(&leftPageNumber, &pageData_[offset], sizeof(int));
		offset = offset + sizeof(int);
		memcpy(key, &pageData_[offset], keySize);
		offset = offset + keySize;
		strStream << " [" << leftPageNumber << "]  ";
		strStream << IndexUtil::keyToString(key, indexHeaderPage_);
	}
	memcpy(&leftPageNumber, &pageData_[offset], sizeof(int));
	strStream << " [" << leftPageNumber << "]" << "\n";
	strStream << "Left Page Number: "<< getLeftPageNumber() << endl;
	strStream << "Right Page Number: "<<getRightPageNumber() << endl;
    strStream << "**********************************************************************"<<endl;
    delete []key;
	return strStream.str();
}

string BPlusTreeNode::toShortString(){
    ostringstream strStream;
	int offset = BPlusTreeNode::getBPlusGeneralNodeHeaderSize();
	int leftPageNumber;
    int keySize = indexHeaderPage_->getKeySize();
	char *key = new char[keySize];
    strStream<<"Page: "<<getPageNumber()<<", ";
    strStream<<"Parent: "<<getParentPageNumber()<<", ";
    strStream<<"Right: "<<getRightPageNumber()<<", ";
    strStream<<"Left: "<<getLeftPageNumber()<<", ";
    strStream<<endl;
	for (int i = 0; i < getNoKeys(); i++) {
		memcpy(&leftPageNumber, &pageData_[offset], sizeof(int));
		offset = offset + sizeof(int);
		memcpy(key, &pageData_[offset], keySize);
		offset = offset + keySize;
		strStream << " [" << leftPageNumber << "]  ";
		strStream << IndexUtil::keyToString(key, indexHeaderPage_);
	}
	memcpy(&leftPageNumber, &pageData_[offset], sizeof(int));
	strStream << " [" << leftPageNumber << "]" << endl;
    delete []key;
    return strStream.str();
}
// Checks if a given page number is present or not within the current node.
bool BPlusTreeNode::isPageNumberPresent(int pageNumber){
    int offset = BPlusTreeNode::getBPlusGeneralNodeHeaderSize();
    int existingPage;
    memcpy(&generalNodePageHeader_, pageData_, sizeof(generalNodePageHeader_));
    memcpy(&existingPage, &pageData_[offset], sizeof(int));
    offset += sizeof(int);
    if(pageNumber == existingPage)
        return true;
    for(int i=0; i<generalNodePageHeader_.noKeys; i++){
        offset += indexHeaderPage_->getKeySize();
        memcpy(&existingPage, &pageData_[offset], sizeof(int));
        offset += sizeof(int);
        if(pageNumber == existingPage)
            return true;
    }
    return false;
}
// Getting all pages of the node
vector<int> BPlusTreeNode::getAllPages(){
    int offset = BPlusTreeNode::getBPlusGeneralNodeHeaderSize();
    int existingPage;
    vector<int> arrPages;
    memcpy(&generalNodePageHeader_, pageData_, sizeof(generalNodePageHeader_));
    memcpy(&existingPage, &pageData_[offset], sizeof(int));
    offset += sizeof(int);
    arrPages.push_back(existingPage);
    for(int i=0; i<generalNodePageHeader_.noKeys; i++){
        offset += indexHeaderPage_->getKeySize();
        memcpy(&existingPage, &pageData_[offset], sizeof(int));
        arrPages.push_back(existingPage);
        offset += sizeof(int);
    }
    return arrPages;
}

// Getting siblings of this node...
STATUS_CODE BPlusTreeNode::getSiblingsToPage(int page, int &leftPageNumber, int &rightPageNumber){
    int offset = BPlusTreeNode::getBPlusGeneralNodeHeaderSize();
    int noKeys = generalNodePageHeader_.noKeys;
    int keySize = indexHeaderPage_->getKeySize();
    int tempLeftPage=-1, tempPage=-1, tempRightPage=-1;
    int i;
    for(i=0; i<noKeys; i++){
        memcpy(&tempPage, &pageData_[offset], sizeof(int));
        offset += (sizeof(int)+keySize);
        memcpy(&tempRightPage, &pageData_[offset], sizeof(int));
        if(tempPage==page){
            // Got the page could be among [1, noKeys] and not the last page
            leftPageNumber = tempLeftPage;
            rightPageNumber = tempRightPage;
            return SUCCESS;
        }
        tempLeftPage = tempPage;
    }
    if(tempRightPage == page){
        // Got the last page to be the one we are checking for
        leftPageNumber = tempPage;
        rightPageNumber = -1;
        return SUCCESS;
    } else{
        // Didnot find the page at all
        leftPageNumber = -1;
        rightPageNumber = -1;
        return FAILURE;
    }
    
}

// Checking the consistency of node considering it's parent, child and sibling
bool BPlusTreeNode::checkConsistency(){
    // ? What to check
    // ? noKeys
    // ? Are all the links maintained properly
    int pageNumber = getPageNumber();
    int parentPageNumber = getParentPageNumber();
    int leftPageNumber = getLeftPageNumber();
    int rightPageNumber = getRightPageNumber();
    int level = getLevel();
    // Checking left, right and parent pages
    bool isConsistent = true;
    if(parentPageNumber!=-1){
        BPlusTreeNode bNode(indexHeaderPage_, parentPageNumber);
        // Searching the page in the node
        isConsistent = bNode.isPageNumberPresent(getPageNumber()) && isConsistent;
    }
    
    if(leftPageNumber!=-1){
        BPlusTreeNode bNode(indexHeaderPage_, leftPageNumber);
        isConsistent = (bNode.getRightPageNumber() == getPageNumber()) && isConsistent;
    }
    if(rightPageNumber!=-1){
        BPlusTreeNode bNode(indexHeaderPage_, rightPageNumber);
        isConsistent = (bNode.getLeftPageNumber() == getPageNumber()) && isConsistent;
    }
    // Checking 
    vector<int> arrPages = getAllPages();
    if(level == 1){
        // Children are leafs
        for(int i=0; i<arrPages.size(); i++){
            BPlusTreeLeafNode bLeaf(indexHeaderPage_, arrPages[i]);
            isConsistent = (bLeaf.getParentPgNumber()==getPageNumber()) && isConsistent;
        }
    } else {
        // Children are non-leafs
        for(int i=0; i<arrPages.size(); i++){
            BPlusTreeNode bLeaf(indexHeaderPage_, arrPages[i]);
            isConsistent = (bLeaf.getParentPageNumber()==getPageNumber()) && isConsistent;
        }
    }
    return isConsistent;
}